// import { throttle } from 'lodash';
import { throttle } from '..';
import { BluetoothErrorHandler, createErrorHandler } from './error-handler';
import { createPacketSplitter, PacketSplitter, TransferDataFn } from './packet-splitter';
import { BluetoothOptions, ConnectionState, Device, EmitEvent, EventData, EventDataMap } from './types';

export class Bluetooth {
  private _deviceId?: string;
  private _connected: ConnectionState = ConnectionState.DISCONNECTED;
  private _deviceList: Device[] = [];
  private _services: UniApp.GetBLEDeviceServicesSuccessData[] = [];
  private _characteristics: UniApp.GetBLEDeviceCharacteristicsSuccessData[] = [];
  private _eventHandlers: { [K in EmitEvent]?: Array<(data: EventData<K>) => void> } = {};
  // onl
  private _hasSetupListeners = false;
  private _options: BluetoothOptions;
  private _scanningTimer: number | undefined;
  private _closeAdapterPromise: Promise<void> | undefined;// 关闭适配器的 Promise

  private _throttleDeviceFound: (res: UniApp.OnBluetoothDeviceFoundResult) => void;
  public packetSplitter: PacketSplitter;
  public errorHandler: BluetoothErrorHandler;

  constructor(options: BluetoothOptions = {}) {
    this._options = {
      deviceNameFilter: /.*/,
      rssiThreshold: -70,
      mtuSize: 32,
      ...options
    };
    this.errorHandler = this._options.createErrorHandler
      ? this._options.createErrorHandler(this)
      : createErrorHandler(this);
    this.packetSplitter = createPacketSplitter({
      chunkSize: this._options.mtuSize,
      ...(this._options.splitterOptions || {})
    });
    this._throttleDeviceFound = throttle((res: UniNamespace.OnBluetoothDeviceFoundResult) => {
      return this._handleDeviceFound(res.devices);
    }, 200)
  }

  // 初始化蓝牙适配器
  async init(): Promise<void> {
    try {
      this._deviceList = [];
      this._services = [];
      this._characteristics = [];
      this._eventHandlers = {};
      await this.disconnect();
      await this._checkPlatformFeatures();
      await this._openAdapter();
      this._setupEventListeners();
    } catch (err) {
      this._handleError(err as Error);
    }
  }

  async scanDevices(timeout = 10000, uuids?: string[]): Promise<typeof this._deviceList | undefined> {
    try {
      if (this._scanningTimer) {
        await this._stopDiscovery();
        await this.sleep(1000);
      }
      this._deviceList = [];
      await this._openAdapter();
      await this._startDiscovery(uuids);
      return new Promise<typeof this._deviceList>((resolve, reject) => {
        this._scanningTimer = setTimeout(() => {
          this._stopDiscovery().then(() => {
            resolve(this._deviceList);
          });
        }, timeout);
        uni.onBluetoothDeviceFound(this._throttleDeviceFound);
      });
    } catch (err) {
      await this._stopDiscovery();
      this._handleError(err as Error);
    }
  }

  // 连接设备
  async connect(deviceId?: string): Promise<void> {
    try {
      if (!deviceId) {
        throw new Error('无效的设备ID');
      }
      if (this._scanningTimer) {
        await this._stopDiscovery();
      }
      await this._openAdapter();
      await uni.createBLEConnection({ deviceId });
      this._deviceId = deviceId;
      this._connected = ConnectionState.CONNECTED;
    } catch (err) {
      this._handleError(err as Error);
    }
  }

  // 发现服务
  async discoverServices(): Promise<void> {
    if (!this._deviceId) {
      console.error('Device ID is not available');
      return;
    }
    try {
      await this.retry(
        async () => {
          const res = await uni.getBLEDeviceServices({
            deviceId: this._deviceId!
          });
          if (!res.services || res.services.length === 0) {
            throw new Error('No services found');
          }
          this._services = res.services;
        }, {
        shouldRetry: () => this._connected === ConnectionState.CONNECTED
      });
    } catch (error) {
      console.error(`Failed to discover `, error);
      throw error;
    }
  }

  // 发现蓝牙特征值
  discoverCharacteristics(serviceId: string) {
    if (!this._deviceId) {
      throw new Error('设备未连接，请先建立连接');
    }
    if (!serviceId?.trim()) {
      throw new Error('无效的服务ID');
    }
    try {
      return this.retry(async () => {
        const { characteristics } = await uni.getBLEDeviceCharacteristics({
          deviceId: this._deviceId!,
          serviceId
        });
        if (!characteristics || characteristics.length === 0) {
          throw new Error('No characteristics found');
        }
        this._characteristics = characteristics;
      }, {
        shouldRetry: () => this._connected === ConnectionState.CONNECTED && !!this._deviceId && !!serviceId
      })
    } catch (err) {
      this._handleError(err as Error);
    }
  }

  // 启用通知
  async startNotification(serviceId: string, characteristicId: string): Promise<void> {
    try {
      if (!this._deviceId) {
        throw new Error('设备未连接，请先建立连接');
      }
      await uni.notifyBLECharacteristicValueChange({
        deviceId: this._deviceId,
        serviceId,
        characteristicId,
        state: true
      });
    } catch (error) {
      this._handleError(error as Error);
    }
  }

  async disconnect(): Promise<void> {
    try {
      if (this._connected === ConnectionState.DISCONNECTED || !this._deviceId) return;
      await uni.closeBLEConnection({ deviceId: this._deviceId });
      this._closeAdapterPromise = this._closeAdapter().then(() => this._closeAdapterPromise = undefined)
      this._connected = ConnectionState.DISCONNECTED;
      this._deviceId = undefined;
    } catch (error) {
      this._handleError(error as Error);
    }
  }

  async unPair(serviceId?: string, characteristicId?: string) {
    try {
      if (this._connected === ConnectionState.DISCONNECTED || !this._deviceId) {
        return;
      }
      if (!characteristicId || !serviceId) {
        throw new Error('无效的服务ID或特征ID');
      }
      const value = new Uint8Array([1]).buffer;
      await this.write(
        serviceId,
        characteristicId,
        value
      );
      return () => {
        // if (typeof uni.removeSavedBluetoothDevices === 'function') {
        //   uni.removeSavedBluetoothDevices();
        // }
      }
    } catch (error) {
      this._handleError(error as Error);
    }
  }

  // 写入数据
  async write(
    serviceId: string,
    characteristicId: string,
    value: ArrayBuffer,
    options: { retry?: number } = {}
  ): Promise<void> {
    const { retry = 2 } = options;
    let attempts = 0;
    while (attempts <= retry) {
      try {
        if (!this._deviceId) {
          throw new Error('设备未连接，请先建立连接');
        }
        await uni.writeBLECharacteristicValue({
          deviceId: this._deviceId,
          serviceId,
          characteristicId,
          value: Array.from(new Uint8Array(value)),
          // 使用 writeNoResponse 前需确认外设支持（通过特征属性 properties 检查）。
          // writeType: 'writeNoResponse' // 明确表明使用无 response 写入方式
        });
        return;
      } catch (err) {
        if (attempts++ >= retry) {
          this._handleError(err as Error);
        } else {
          await new Promise((resolve) => setTimeout(resolve, 300));
        }
      }
    }
  }

  async send(data: Uint8Array, fn: TransferDataFn, packetSequenceStart?: number): Promise<void> {
    if (!this._deviceId) {
      throw new Error('设备未连接，请先建立连接');
    }
    return this.packetSplitter.send(data, fn, packetSequenceStart);
  }

  async setMTU(size = 128): Promise<void> {
    try {
      await uni.setBLEMTU({
        deviceId: this._deviceId!,
        mtu: size
      });
    } catch (error) {
      this._handleError(error as Error);
    }
  }

  // 获取当前状态
  getState() {
    return {
      deviceId: this._deviceId!,
      connected: this._connected,
      services: [...this._services],
      characteristics: [...this._characteristics],
      devices: [...this._deviceList]
    };
  }

  // 事件监听
  on<K extends EmitEvent>(event: K, listener: (data: EventDataMap[K]) => void): this {
    if (!this._eventHandlers[event]) {
      this._eventHandlers[event] = [];
    }
    (this._eventHandlers[event] as Array<(data: EventDataMap[K]) => void>).push(listener);
    return this;
  }
  once<K extends EmitEvent>(event: K, listener: (data: EventDataMap[K]) => void): this {
    const onceListener = (data: EventDataMap[K]) => {
      listener(data);
      this.off(event, onceListener);
    };
    return this.on(event, onceListener);
  }
  // 移除监听
  off<K extends EmitEvent>(event: K, listener: (data: EventDataMap[K]) => void): this {
    const handlers = this._eventHandlers[event] as Array<(data: EventDataMap[K]) => void> | undefined;
    if (handlers) {
      (this._eventHandlers[event] as any) = handlers.filter((h) => h !== listener);
    }
    return this;
  }

  async retry<T>(
    operation: () => Promise<T>,
    options?: {
      maxRetries?: number,
      initialDelay?: number,
      shouldRetry?: (error: any) => boolean
    }
  ): Promise<T> {
    const { maxRetries = 3, initialDelay = 1000, shouldRetry = () => true } = options || {}
    let retryCount = 0;
    let currentDelay = initialDelay;
    while (retryCount < maxRetries) {
      try {
        return await operation();
      } catch (error) {
        retryCount++;
        if (retryCount >= maxRetries || !shouldRetry(error)) {
          throw error;
        }
        // 使用指数退避计算等待时间
        const delay = Math.min(currentDelay * 2, 10000); // 最大不超过10秒
        console.log(`Retry ${retryCount}/${maxRetries} - Waiting ${delay}ms...`);
        await this.sleep(delay);
        currentDelay = delay;
      }
    }
    throw new Error(`Operation failed after ${maxRetries} retries`);
  }

  sleep(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  arrayBufferToHexString = (buffer: ArrayBuffer) => {
    if (buffer.byteLength === 0) return ''
    return Array.from(new Uint8Array(buffer))
      .map((b) => b.toString(16).padStart(2, '0'))
      .join(' ');
  };

  stringToUint8Array(str: string): Uint8Array {
    // 方案1：优先使用TextEncoder（浏览器/Node环境）
    if (typeof TextEncoder !== 'undefined') {
      return new TextEncoder().encode(str);
    }
    // 方案2：微信小程序兼容实现
    const bytes: number[] = [];
    for (let i = 0; i < str.length; i++) {
      const code = str.charCodeAt(i);
      if (code <= 0x7f) {
        bytes.push(code);
      } else if (code <= 0x7ff) {
        bytes.push(0xc0 | (code >> 6));
        bytes.push(0x80 | (code & 0x3f));
      } else if (code <= 0xffff) {
        bytes.push(0xe0 | (code >> 12));
        bytes.push(0x80 | ((code >> 6) & 0x3f));
        bytes.push(0x80 | (code & 0x3f));
      } else {
        bytes.push(0xf0 | (code >> 18));
        bytes.push(0x80 | ((code >> 12) & 0x3f));
        bytes.push(0x80 | ((code >> 6) & 0x3f));
        bytes.push(0x80 | (code & 0x3f));
      }
    }
    return new Uint8Array(bytes);
  }

  withResponseHandler<T = ArrayBuffer>(
    commandStarter: () => void,
    responseHandler: (
      data: EventDataMap[EmitEvent.data],
      succeed: (data: T) => void,
      fail: (error: string | Error) => void
    ) => void,
    options: { timeout?: number } = {}
  ): Promise<T> {
    return new Promise<T>((resolve, reject) => {
      let isCompleted = false;
      let timeoutId: number;

      const complete = () => {
        if (!isCompleted) {
          clearTimeout(timeoutId);
          this.off(EmitEvent.data, onResponse);
          isCompleted = true;
        }
      };

      const succeed = (data: T) => {
        complete();
        resolve(data);
      };

      const fail = (error: string | Error) => {
        complete();
        reject(error instanceof Error ? error : new Error(error));
      };

      const onResponse = (data: EventDataMap[EmitEvent.data]) => {
        try {
          responseHandler(data, succeed, fail);
        } catch (error) {
          fail(error instanceof Error ? error : new Error('响应处理异常'));
        }
      };

      // 设置超时
      timeoutId = setTimeout(() => {
        fail(`操作超时 (${options.timeout || 5000}ms)`);
      }, options.timeout || 5000);
      // 注册事件监听
      this.on(EmitEvent.data, onResponse);
      // 执行命令
      try {
        commandStarter();
      } catch (error) {
        fail(error instanceof Error ? error : new Error('命令启动失败'));
      }
    });
  }

  // 私有方法
  private async _checkPlatformFeatures(): Promise<void> {
    if (typeof uni.openBluetoothAdapter !== 'function') {
      throw new Error('当前环境不支持蓝牙功能');
    }
  }

  private async _openAdapter() {
    const getAdapterState = async (): Promise<boolean> => {
      try {
        const res = await uni.getBluetoothAdapterState();
        return res.available;
      } catch (err) {
        return false;
      }
    };
    try {
      if (this._closeAdapterPromise) {
        await this._closeAdapterPromise;
      }
      let available = await getAdapterState();
      if (available) return true;
      await uni.openBluetoothAdapter();
      return await getAdapterState();
    } catch (error) {
      this._handleError(error as Error);
    }
  }

  private async _closeAdapter(): Promise<void> {
    try {
      this.retry(async () => {
        await uni.closeBluetoothAdapter();
      })
      await this.sleep(1000)
    } catch (error) {
      this._handleError(error as Error);
    }
  }

  private _setupEventListeners(): void {
    if (this._hasSetupListeners) return;
    this._hasSetupListeners = true;
    uni.onBLEConnectionStateChange((res) => {
      this._connected = res.connected ? ConnectionState.CONNECTED : ConnectionState.DISCONNECTED;
      this._emit(EmitEvent.connectionStateChange, res);
    });

    uni.onBLECharacteristicValueChange((res) => {
      this._emit(EmitEvent.data, {
        deviceId: res.deviceId,
        serviceId: res.serviceId,
        characteristicId: res.characteristicId,
        value: res.value as unknown as ArrayBuffer
      });
    });

    uni.onBluetoothAdapterStateChange((res) => {
      this._emit(EmitEvent.adapterStateChange, {
        available: res.available,
        discovering: res.discovering
      });
    });
  }

  private async _startDiscovery(uuids?: string[]): Promise<void> {
    try {
      await uni.startBluetoothDevicesDiscovery({
        allowDuplicatesKey: true,
        powerLevel: 'high',
        services: uuids,
      });
    } catch (error) {
      this._handleError(error as Error);
    }
  }

  private async _stopDiscovery(): Promise<void> {
    if (this._scanningTimer) {
      clearTimeout(this._scanningTimer);
      this._scanningTimer = undefined;
    }
    if (uni.offBluetoothDeviceFound) {
      uni.offBluetoothDeviceFound(this._throttleDeviceFound as any);
    }
    try {
      await uni.stopBluetoothDevicesDiscovery();
      await this.sleep(1000);
    } catch (err) {
      await this._openAdapter()
      return
    }
  }

  private _handleDeviceFound(devices: Device[]): void {
    const validDevices = devices.filter(
      (device) =>
        device.name?.match(this._options.deviceNameFilter!) &&
        (device.RSSI ?? -Infinity) > (this._options.rssiThreshold ?? -70)
    );
    validDevices.forEach((newDevice) => {
      const exists = this._deviceList.some((d) => d.deviceId === newDevice.deviceId);
      if (!exists) {
        this._deviceList.push(newDevice);
        this._emit(EmitEvent.deviceFound, newDevice);
      }
    });
  }

  private _emit<K extends EmitEvent>(event: K, data: EventDataMap[K]): void {
    const handlers = this._eventHandlers[event] as Array<(data: EventDataMap[K]) => void> | undefined;
    handlers?.forEach((handler) => handler(data));
  }

  private _handleError(err: any): void {
    const errorMap: Record<number, string> = {
      10000: '未初始化蓝牙适配器',
      10001: '当前蓝牙适配器不可用',
      10002: '没有找到指定设备',
      10003: '连接失败',
      10004: '没有找到指定服务',
      10005: '没有找到指定特征值',
      10006: '当前连接已断开',
      10007: '当前特征值不支持此操作',
      10008: '其余所有系统上报的异常',
      10009: '系统特有错误：iOS特有异常',
      10010: '连接超时'
    };
    if ('errCode' in err) {
      (err as any).errMsg = errorMap[err.errCode] || err.errMsg;
    }
    this.errorHandler?.handle(err);
    throw err;
  }
}